package pikes.uri;

import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

import pikes.core.AbstractPrintable;

public class RelativeURI extends AbstractPrintable implements URI {

	private Path path = null;

	private URI parent = null;

	private Map<CharSequence, CharSequence> parameters = new LinkedHashMap<CharSequence, CharSequence>();

	public RelativeURI(final URI parent, final CharSequence path) {
		this(path);
		this.parent = parent;
	}

	public RelativeURI(final URI parent, final CharSequence path, final Map<CharSequence, CharSequence> parameters) {
		this(parent, path);
		if (parameters == null) {
			throw new IllegalArgumentException();
		}
		this.parameters = parameters;
	}

	public RelativeURI(final CharSequence path) {
		this.path = new Path(path);
	}

	public RelativeURI(final CharSequence path, final Map<CharSequence, CharSequence> parameters) {
		this(path);
		if (parameters == null) {
			throw new IllegalArgumentException();
		}
		this.parameters = parameters;
	}

	public final void print(Appendable appendable) throws IOException {
		if (parent != null) {
			parent.print(appendable);
		}
		path.print(appendable);
		if (!parameters.isEmpty()) {
			appendable.append('?');
			Iterator<Map.Entry<CharSequence, CharSequence>> iEntrySet = parameters.entrySet().iterator();

			while (iEntrySet.hasNext()) {
				Map.Entry<CharSequence, CharSequence> queryEntry = iEntrySet.next();

				appendable.append(queryEntry.getKey());
				appendable.append('=');
				appendable.append(queryEntry.getValue());

				if (iEntrySet.hasNext()) {
					appendable.append('&');
				}
			}
		}
	}

	@Override
	public final boolean equals(Object obj) {
		if (obj instanceof RelativeURI) {
			RelativeURI relURI = (RelativeURI) obj;

			boolean equals = path.equals(relURI.path);

			if (!equals) {
				return false;
			}

			equals = parameters.equals(relURI.parameters);

			return equals;
		}
		else {
			return false;
		}
	}

	@Override
	public final int hashCode() {
		return path.hashCode();
	}

}

class Path extends AbstractPrintable {

	private CharSequence path = null;

	public Path(final CharSequence path) {
		super();
		this.path = path;
	}

	public void print(Appendable appendable) throws IOException {
		if (path.length() > 0) {
			if ('/' != path.charAt(0)) {
				appendable.append('/');
			}
			appendable.append(path);
		}
	}

	@Override
	public boolean equals(Object obj) {
		return toString().equals(obj.toString());
	}

	@Override
	public int hashCode() {
		return toString().hashCode();
	}

}
